package com.astrob.activitys;

import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Criteria;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.GpsStatus.NmeaListener;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.PowerManager;
import android.widget.Toast;

import com.astrob.model.GeoHash;
import com.astrob.model.LonLat;
import com.astrob.naviframe.Start;
import com.astrob.nhcmap.R;
import com.astrob.util.SysUtils;
import com.nhc.database.dbmodel.TrackPoint;
import com.nhc.model.TripDataFileHandle;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;

//模拟位置
//android 自带location除了可以输出gps的经纬度信息，还可以进行传入location数据，进行模拟输出。输出模拟的位置信息可以在同一个应用程序，也可以给其他应用app使用。
//https://blog.csdn.net/qq_16064871/article/details/72836027
public class GPSProvider {

    public interface NetPosCallBack {
        // 刷新网络位置
        void updateNetPos(LonLat netPos);
    }

    public NetPosCallBack mNetCallback = null;

    private Context mContext;
    private LocationManager mlocManager = null;
    private Location mlastValidLoc = null;

    private LocationManager networkLocationManager;
    private Location mNetValidLoc = null;
    private static final int MINTIME = 2000;
    private static final int MININSTANCE = 2;

    private GpsStatus mGpsStatus = null;
    private Iterable<GpsSatellite> mAllSatellites = null;
    private boolean mFixed = false;

    private PowerManager pm;
    private PowerManager.WakeLock wakeLock;

    private static GPSProvider instance = new GPSProvider();

    public static GPSProvider getInstance() {
        return instance;
    }

    public GPSProvider() {
    }

    public boolean mHaveNMEALog = false;//NMEALogProvider传入，如果用了NMEALog，则不用gps记录航迹

    private boolean mNeedSaveGpslog = false;
    private FileOutputStream fos = null;
    private FileOutputStream fos2 = null;

    public boolean isNeedNeedSaveGpslog() {
        return mNeedSaveGpslog;
    }

    public void initGPSProvider(Context context) {
        mContext = context;

        //是否记录GPSlog
        try {
            File file = new File(Start.RUNDIR + "/SaveGpslog.txt");
            if (file.exists()) {
                mNeedSaveGpslog = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

//        http://blog.csdn.net/k763925053/article/details/8158667
        pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        //保持cpu一直运行，不管屏幕是否黑屏
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CPUKeepRunning");
        wakeLock.acquire();

        // GPS定位
        try {
            mlocManager = (LocationManager) mContext
                    .getSystemService(Context.LOCATION_SERVICE);
            mlocManager.addNmeaListener(nmeaListener);
            mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                    1000, 0, mlocListener);
        } catch (Exception e) {
            return;
        }

        // 基站定位
        try {
            networkLocationManager = (LocationManager) mContext
                    .getSystemService(Context.LOCATION_SERVICE);
            networkLocationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER, MINTIME, MININSTANCE,
                    netlocationListener);
        } catch (Exception e) {
            return;
        }

        openGpsStatus();

        openGPS();
    }

    NmeaListener nmeaListener = new NmeaListener() {
        @SuppressLint("SimpleDateFormat")
        @Override
        public void onNmeaReceived(long timestamp, String nmea) {
            try {
                if (!mNeedSaveGpslog || nmea.length() < 50
                /* || !nmea.contains("$GPRMC") */)
                    return;

                if (fos == null) {
                    try {
                        SimpleDateFormat formatter = new SimpleDateFormat(
                                "MMdd-HHmm");
                        Date curDate = new Date(System.currentTimeMillis());
                        String sufix = formatter.format(curDate);
                        fos = new FileOutputStream(Start.RUNDIR + "/nmea"
                                + sufix + ".txt");
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                } else {
                    fos.write(nmea.getBytes());
                    fos.flush();
                }
            } catch (Exception e) {
            }
        }
    };

    public void openGpsStatus() {
        mlocManager.addGpsStatusListener(mStatusListener);
    }

    public void closeGpsStatus() {
        mlocManager.removeGpsStatusListener(mStatusListener);
    }

    public boolean isGPSEnabled() {
        if (mlocManager == null)
            return false;
        return mlocManager
                .isProviderEnabled(android.location.LocationManager.GPS_PROVIDER);
    }

    public void openGPS() {
        if (mlocManager == null)
            return;

        if (mlocManager
                .isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) {
            Toast.makeText(mContext, R.string.gpsykq, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(mContext, R.string.gpswkqbndh, Toast.LENGTH_SHORT).show();
        }

        // new AlertDialog.Builder(mContext)
        // .setTitle(mContext.getString(R.string.dlg_title))
        // .setMessage(mContext.getString(R.string.opengpssetting_tip))
        // .setPositiveButton(mContext.getString(R.string.yes), new
        // DialogInterface.OnClickListener() {
        //
        // @Override public void onClick(DialogInterface dialog, int which) {
        // Intent intent = new Intent(
        // Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        // mContext.startActivity(intent); } })
        // .setNegativeButton(mContext.getString(R.string.cancel), null)
        // .show();

    }

    private String getProvider() {
        if (mlocManager == null)
            return null;

        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        criteria.setAltitudeRequired(false);
        criteria.setBearingRequired(false);
        criteria.setCostAllowed(true);
        criteria.setPowerRequirement(Criteria.POWER_LOW);

        return mlocManager.getBestProvider(criteria, true);
    }

    private final LocationListener netlocationListener = new LocationListener() {

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onProviderDisabled(String provider) {
        }

        public void onLocationChanged(Location location) {
            if (location != null) {
                mNetValidLoc = location;
                double longitude = mNetValidLoc.getLongitude();
                double latitude = mNetValidLoc.getLatitude();
//                CLonLat ll = NavFrameSDK.getInstance().new CLonLat();
//                ll.lon = longitude;
//                ll.lat = latitude;
//
//                NavFrameSDK.DecodeLonLat(ll);
//                latitude = ll.lat;
//                longitude = ll.lon;

                LonLat ll = new LonLat(longitude, latitude);

                if (mNetCallback != null) {
                    mNetCallback.updateNetPos(ll);
                }

                long datetime = System.currentTimeMillis();
                if (location.getTime() >= datetime) {
                    datetime = location.getTime();
                }

                //时间需大于2017年
                if (!mHaveNMEALog && ll.IsValid() && datetime > 1497921620000L && mFixed) {
                    saveLL(ll);
                    GeoHash g = new GeoHash(ll);
                    g.sethashLength(10);//精确到1米
                    String geohash = g.getGeoHashBase32();
                    TrackPoint trackPoint = new TrackPoint(null, longitude, latitude, location.getAltitude(),
                            location.getSpeed(), location.getBearing(),
                            location.getAccuracy(), datetime, 0L, geohash, "");
                    SysUtils.getInstance().saveTrackPoint(trackPoint);
                }
            }
        }
    };

    private final LocationListener mlocListener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            if (location != null) {
                mlastValidLoc = location;
                double longitude = mlastValidLoc.getLongitude();
                double latitude = mlastValidLoc.getLatitude();
//                CLonLat ll = NavFrameSDK.getInstance().new CLonLat();
//                ll.lon = longitude;
//                ll.lat = latitude;
//                NavFrameSDK.DecodeLonLat(ll);
//                mlastValidLoc.setLatitude(ll.lat);
//                mlastValidLoc.setLongitude(ll.lon);

                LonLat ll = new LonLat(longitude, latitude);

                long datetime = System.currentTimeMillis();
                if (mlastValidLoc.getTime() >= datetime) {
                    datetime = mlastValidLoc.getTime();
                }

                //时间需大于2017年
                if (!mHaveNMEALog && ll.IsValid() && datetime > 1497921620000L && mFixed) {
                    //存原始坐标?还是都存纠偏的坐标吧，原始坐标使用的几率低，如果需要再转
                    saveLL(ll);
                    GeoHash g = new GeoHash(ll);
                    g.sethashLength(10);//精确到1米
                    String geohash = g.getGeoHashBase32();
                    TrackPoint trackPoint = new TrackPoint(null, longitude, latitude, mlastValidLoc.getAltitude(),
                            mlastValidLoc.getSpeed(), mlastValidLoc.getBearing(),
                            mlastValidLoc.getAccuracy(), datetime, 0L, geohash, "");
                    SysUtils.getInstance().saveTrackPoint(trackPoint);
                }
            }
        }

        @Override
        public void onProviderDisabled(String provider) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            if (status == LocationProvider.AVAILABLE) {
                mFixed = true;
            } else if (status == LocationProvider.OUT_OF_SERVICE) {
                mFixed = false;
            } else if (status == LocationProvider.TEMPORARILY_UNAVAILABLE) {
                mFixed = false;
            }
        }
    };

    private void saveLL(LonLat ll) {
        SysUtils.getInstance().saveLL(ll);
    }

    public Iterable<GpsSatellite> GetSatellite() {
        return mAllSatellites;
    }

    private final GpsStatus.Listener mStatusListener = new GpsStatus.Listener() {
        @Override
        public void onGpsStatusChanged(int event) {
            mGpsStatus = mlocManager.getGpsStatus(null);

            switch (event) {
                case GpsStatus.GPS_EVENT_FIRST_FIX:
                    mGpsStatus.getTimeToFirstFix();
                    break;
                case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                    mAllSatellites = mGpsStatus.getSatellites();
                    setSatelliteList();
                    break;
                case GpsStatus.GPS_EVENT_STARTED:
                    break;
                case GpsStatus.GPS_EVENT_STOPPED:
                    break;
                default:
                    break;
            }
        }
    };

    public float getSpeed() {
        if (mlastValidLoc == null || !mFixed)
            return (float) 0.0;

        return mlastValidLoc.getSpeed();
    }

    public float getDirection() {
        if (mlastValidLoc == null)
            return (float) 0.0;
        return mlastValidLoc.getBearing();
    }

    public float getAccuracy() {
        if (mlastValidLoc == null)
            return 100;
        return mlastValidLoc.getAccuracy();
    }

    public long getTime() {
        if (mlastValidLoc == null)
            return 0;
        return mlastValidLoc.getTime();
    }

    public LonLat getPos() {
        if (mlastValidLoc == null)
            return null;
        LonLat pos = new LonLat(mlastValidLoc.getLongitude(),
                mlastValidLoc.getLatitude());
        return pos;
    }

    public double getAltitude() {
        if (mlastValidLoc == null)
            return 0;
        return mlastValidLoc.getAltitude();
    }

    public boolean isFixed() {
        return mFixed;
    }

    public int getGPSNum() {
        if (mGpsStatus == null || mAllSatellites == null)
            return 0;

        mSatelliteList.clear();
        int count = 0;
        try {
            for (Iterator<GpsSatellite> it = mAllSatellites.iterator(); it
                    .hasNext(); ) {
                GpsSatellite gpsState = it.next();
                mSatelliteList.add(gpsState);
                if (gpsState.usedInFix())
                    count++;
            }
        } catch (Exception e) {

        }
        return count;
    }

    private ArrayList<GpsSatellite> mSatelliteList = new ArrayList<GpsSatellite>();

    public ArrayList<GpsSatellite> getGpsSatellite() {
        return mSatelliteList;
    }

    private final int MAX_GPS_SATELLITE_NUM = 32;
    public int nPRN[] = new int[MAX_GPS_SATELLITE_NUM];
    ;
    public float nSNR[] = new float[MAX_GPS_SATELLITE_NUM];
    public float nElevation[] = new float[MAX_GPS_SATELLITE_NUM];
    public float nAzimuth[] = new float[MAX_GPS_SATELLITE_NUM];

    private void setSatelliteList() {
        if (mGpsStatus == null)
            return;

        mSatelliteList.clear();
        int count = 0;
        for (Iterator<GpsSatellite> it = mAllSatellites.iterator(); it
                .hasNext(); ) {
            GpsSatellite gpsState = it.next();
            mSatelliteList.add(gpsState);
            if (gpsState.usedInFix())
                count++;
        }

        if (count >= 4) {
            mFixed = true;
        } else {
            mFixed = false;
        }

        for (int i = 0; i < mSatelliteList.size() && i < MAX_GPS_SATELLITE_NUM; i++) {
            nAzimuth[i] = mSatelliteList.get(i).getAzimuth();
            nElevation[i] = mSatelliteList.get(i).getElevation();
            nSNR[i] = mSatelliteList.get(i).getSnr();
            nPRN[i] = mSatelliteList.get(i).getPrn();
        }
    }

}
